/*
*********************************************************************************************************
*
*	模块名称 : 环形队列的实现
*	文件名称 : Ringbuff.c
*	版    本 : V1.0
*	说    明 : 实现环形队列的创建、删除、清空、写入和读出。
*			   
*	修改记录 :
*		版本号      日期            作者                 说明
*		 V1.0    2021-02-19     zhengzhiqiang         正式发布
*
*********************************************************************************************************		
*/
#include <string.h>
#include "zb32l03x_hal.h"
#include "Ringbuff.h"





#define min(a,b)  (((uint32_t)a)>((uint32_t)b) ? (b) : (a)) 


/*********************** 内部调用函数 ******************************/

#if RINGBUFF_USE_MUTEX
static  TX_MUTEX   AppRingSemp;    /* 用于printf互斥 */

/* 创建互斥信号量 */

/*
*********************************************************************************************************
*	功能说明: 创建队列的互斥量。
*	形    参: mutex :互斥量句柄
*	返 回 值: 无
* 说    明：
*********************************************************************************************************
*/
ERR_E RingBuff_Create_Mutex(MUTEX_T *mutex)
{
   UINT  status;
   status=tx_mutex_create(mutex,"AppRingSemp",TX_INHERIT);
   if(status!=TX_SUCCESS)
   {
     return ERR_RING_INVALID_MUTEX;
   }
   else
   {
     return ERR_NONE;
   } 
  
}
/*
*********************************************************************************************************
*	功能说明: 删除队列的互斥量。
*	形    参: mutex :互斥量句柄
*	返 回 值: 无
* 说    明：
*********************************************************************************************************
*/
ERR_E RingBuff_Deleta_Mutex(MUTEX_T *mutex)
{
	 UINT  status;
   status=tx_mutex_delete(mutex);
   if(status!=TX_SUCCESS)
   {
     return ERR_RING_INVALID_MUTEX;
   }
   else
   {
     return ERR_NONE;
   } 

}
/*
*********************************************************************************************************
*	功能说明: 请求一个互斥量，得到互斥量的线程才允许进行访问缓冲区。
*	形    参: mutex :互斥量句柄
*	返 回 值: 无
* 说    明：
*********************************************************************************************************
*/
ERR_E RingBuff_Request_Mutex(MUTEX_T *mutex)
{
  UINT status;
  /* 互斥操作 */
  status=tx_mutex_get(mutex, MUTEX_TIMEOUT);
  if (status != TX_SUCCESS)
  {
    return ERR_RING_INVALID_MUTEX;
  }
  else
  {
    return ERR_NONE;
  }
}

/*
*********************************************************************************************************
*	功能说明: 释放互斥量，当线程使用完资源必须释放互斥量。
*	形    参: mutex :互斥量句柄
*	返 回 值: 无
* 说    明：
*********************************************************************************************************
*/
ERR_E RingBuff_Release_Mutex(MUTEX_T *mutex)
{
  UINT status;
  status = tx_mutex_put(mutex);
  if (status != TX_SUCCESS)
  {
    return ERR_RING_INVALID_MUTEX;
  }
  else
  {
    return ERR_NONE;
  }
}
#endif

/*
*********************************************************************************************************
*	功能说明: 找出当前数的二进制中最大位为1位的位置。
*	形    参: x:需要计算的数
*	返 回 值: 无
* 说    明：
*********************************************************************************************************
*/
static uint32_t fls(uint32_t x)
{
  int r = 32;

  if (!x)
    return 0;
  if (!(x & 0xffff0000u))
  {
    x <<= 16;
    r -= 16;
  }
  if (!(x & 0xff000000u))
  {
    x <<= 8;
    r -= 8;
  }
  if (!(x & 0xf0000000u))
  {
    x <<= 4;
    r -= 4;
  }
  if (!(x & 0xc0000000u))
  {
    x <<= 2;
    r -= 2;
  }
  if (!(x & 0x80000000u))
  {
    x <<= 1;
    r -= 1;
  }
  return r;
}

/*
*********************************************************************************************************
*	功能说明: 用于处理数据，使数据长度必须为 2^n
*					 如果不是，则转换，丢弃多余部分，如
*					 roundup_pow_of_two(66) -> 返回 64
*	形    参: x:需要计算的数
*	返 回 值: 无
* 说    明：
*********************************************************************************************************
*/
static uint32_t roundup_pow_of_two(uint32_t x)
{
	return (1 << (fls(x-1)-1));				//向下对齐
}

/*
*********************************************************************************************************
*	功能说明: 创建一个环形缓冲区
*	形    参: rb：环形缓冲区句柄 
*           buffer：环形缓冲区的数据区域
*           len：环形缓冲区的大小，缓冲区大小要为2^n
*	返 回 值: ERR_OK：创建成功 ERR_NOK：创建失败
* 说    明：
*********************************************************************************************************
*/

ERR_E RingBuff_Create(Ring_t *rb, uint8_t *buffer, uint32_t len)
{

  
  if (rb == NULL)
  {
    
    return ERR_RING_INVALID_P_ADDR;
  }

  if (buffer == NULL)
  {
    return ERR_RING_INVALID_P_MEM;
  }

  if (len == 0)
  {
    return ERR_RING_INVALID_SIZE;
  }

  if (len & (len - 1)) /*判断长度是否为2^n字节*/
  {
    len = roundup_pow_of_two(len);
    return ERR_RING_INVALID_SIZE;
  }

  rb->buffer = buffer;
  rb->len = len;
  rb->in = rb->out = 0;
  memset(buffer,0,len);
#if RINGBUFF_USE_MUTEX
  rb->mutex=&AppRingSemp;
  /* 创建信号量不成功 */
  if (RingBuff_Create_Mutex(rb->mutex))
  {
    return ERR_RING_INVALID_MUTEX;
  }
#endif

  return ERR_NONE;
}

/*
*********************************************************************************************************
*	功能说明: 删除一个环形缓冲区
*	形    参: rb：环形缓冲区句柄 
*	返 回 值: ERR_OK：删除成功 ERR_NOK：删除失败
* 说    明：
*********************************************************************************************************
*/
ERR_E RingBuff_Delete(Ring_t *rb)
{
	
  if(rb == NULL)
	{
		return ERR_RING_INVALID_P_ADDR;
	}
	
	rb->buffer = NULL;
	rb->len = 0;
	rb->in = rb->out = 0;
#if RINGBUFF_USE_MUTEX
  if(RingBuff_Deleta_Mutex(rb->mutex))
  {
    
    return ERR_RING_INVALID_MUTEX;
  }
#endif
	 return ERR_NONE;
}

/*
*********************************************************************************************************
*	功能说明: 清空一个环形缓冲区
*	形    参: rb：环形缓冲区句柄 
*	返 回 值: ERR_OK：成功 ERR_NOK：失败
* 说    明：
*********************************************************************************************************
*/
ERR_E RingBuff_Clear(Ring_t *rb)
{
	if(rb == NULL)
	{
		return ERR_RING_INVALID_P_ADDR;

	}
	rb->in = rb->out = 0;
#if RINGBUFF_USE_MUTEX	
  if(RingBuff_Release_Mutex(rb->mutex))
  {
    return ERR_RING_INVALID_MUTEX;
  }
#endif
	 return ERR_NONE;
}

/*
*********************************************************************************************************
*	功能说明:  从buff空间拷贝len字节长度的数据到rb环形缓冲区中的空闲空间
*	形    参: rb：环形缓冲区句柄 
*           wbuff:写入的数据起始地址
*           len:写入数据的长度(字节)
*	返 回 值: 实际写入长度
* 说    明：
*********************************************************************************************************
*/
uint32_t RingBuff_Write(Ring_t *rb,const uint8_t* wbuff,uint32_t len, ERR_E *err)
{
  uint32_t l=0;
#if RINGBUFF_USE_MUTEX
  /* 请求互斥量，成功才能进行ringbuff的访问 */
  if(RingBuff_Request_Mutex(rb->mutex))
  {
    *err = ERR_RING_INVALID_MUTEX;
    return 0;
  }
  else  /* 获取互斥量成功 */
  {
#endif
    len = min(len, rb->len - rb->in + rb->out);

    /* 第一部分的拷贝:从环形缓冲区写入数据直至缓冲区最后一个地址 */
    l = min(len, rb->len - (rb->in & (rb->len - 1)));
    memcpy(rb->buffer + (rb->in & (rb->len - 1)), wbuff, l);
    /* 如果溢出则在缓冲区头写入剩余的部分，如果没溢出这句代码相当于无效 */
    memcpy(rb->buffer, wbuff + l, len - l);

 

    rb->in += len;

#if RINGBUFF_USE_MUTEX
  }
  /* 释放互斥量 */
  RingBuff_Release_Mutex(rb->mutex);
#endif
 *err = ERR_NONE;
  return len;
}

/*
*********************************************************************************************************
*	功能说明:  从buff空间拷贝len字节长度的数据到rb环形缓冲区中的空闲空间
*	形    参: rb：环形缓冲区句柄 
*           rbuff:读入的数据起始地址
*           len:读入数据的长度(字节)
*	返 回 值: 实际读入长度
* 说    明：
*********************************************************************************************************
*/

uint32_t RingBuff_Read(Ring_t *rb,uint8_t* rbuff, uint32_t len, ERR_E *err)
{
  uint32_t l=0;
#if RINGBUFF_USE_MUTEX
  /* 请求互斥量，成功才能进行ringbuff的访问 */
  if(RingBuff_Request_Mutex(rb->mutex))
  {
    *err = ERR_RING_INVALID_MUTEX;
    return 0;
  }
  else  /* 获取互斥量成功 */
  {
#endif
    len = min(len, rb->in - rb->out);

     
    /* 第一部分的拷贝:从环形缓冲区读取数据直至缓冲区最后一个 */
    l = min(len, rb->len - (rb->out & (rb->len - 1)));
    memcpy(rbuff, rb->buffer + (rb->out & (rb->len - 1)), l);

    /* 如果溢出则在缓冲区头读取剩余的部分如果没溢出这句代码相当于无效 */
    memcpy(rbuff + l, rb->buffer, len - l);

    
    rb->out += len;

    
#if RINGBUFF_USE_MUTEX
  }
  /* 释放互斥量 */
  RingBuff_Release_Mutex(rb->mutex);
#endif
  *err = ERR_NONE;
  return len;
}

/*
*********************************************************************************************************
*	功能说明:  获取队列的长度
*	形    参: rb：环形缓冲区句柄 
*           
*           
*	返 回 值: 长度
* 说    明：
*********************************************************************************************************
*/

uint32_t RingBuff_GetLen(Ring_t *rb)
{
  uint32_t len = 0;
#if RINGBUFF_USE_MUTEX
  /* 请求互斥量，成功才能进行ringbuff的访问 */
  if (RingBuff_Request_Mutex(rb->mutex))
  {
    *err = ERR_RING_INVALID_MUTEX;
    return 0;
  }
  else /* 获取互斥量成功 */
  {
#endif
    len = rb->in - rb->out;

#if RINGBUFF_USE_MUTEX
  }
  /* 释放互斥量 */
  RingBuff_Release_Mutex(rb->mutex);
#endif
  return len;
}
